package com.kim.file;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.codec.digest.DigestUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class FileUtils implements FileBase {

	/**
	 * 文件加载完毕回调接口
	 * 
	 * @author Kimhuang
	 * 
	 */
	public interface FileLoadCallback {

		/**
		 * 文件加载完毕回调方法
		 * 
		 * @param fileSavePath
		 * @param inputStream
		 */
		public void loadComplete(String fileSavePath, InputStream inputStream);

		/**
		 * 文件加载完毕回调方法
		 * 
		 * @param txt
		 */
		public void loadComplete(String txt);

		/**
		 * 文件加载完毕回调方法
		 * 
		 * @param drawable
		 * @param localPath
		 */
		public void loadComplete(Drawable drawable, String localPath);
	}

	public static final String loadLocalFileAsTxt(String localFilePath)
			throws FileNotFoundException {

		InputStream inputStream = null;
		try {
			inputStream = getFileInputStreamLocal(localFilePath);
			return inputStream2String(inputStream);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				inputStream = null;
			}
		}
		return null;
	}

	/**
	 * 保存图片到data目录下
	 * 
	 * @param bitmap
	 * @param filePath
	 * @throws FileNotFoundException
	 */
	public static final void saveBitmap2DataDir(Bitmap bitmap, String fileName,
			Context context) throws FileNotFoundException {
		FileOutputStream fileOutputStream = context.openFileOutput(fileName,
				Context.MODE_PRIVATE);
		bitmap.compress(CompressFormat.PNG, 100, fileOutputStream);
	}

	/**
	 * 保存图片到sdcard目录下
	 * 
	 * @param bitmap
	 * @param fileName
	 * @param filePath
	 * @throws FileNotFoundException
	 */
	public static final void saveBitmap2SDCard(Bitmap bitmap, String fileName,
			String filePath) throws FileNotFoundException {
		FileOutputStream fileOutputStream = new FileOutputStream(new File(
				filePath + "/" + fileName));
		bitmap.compress(CompressFormat.PNG, 100, fileOutputStream);
	}

	/**
	 * 根据本地路径加载Drawable文件
	 * 
	 * @param filePath
	 * @param size
	 * @return
	 * @throws FileNotFoundException
	 */
	public static final Drawable loadDrawableFromLoaclByLocalPath(
			String filePath, int size) throws FileNotFoundException {

		InputStream inputStream = getFileInputStreamLocal(filePath);

		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inPreferredConfig = Bitmap.Config.RGB_565; // 减少颜色通道占用空间
		options.inSampleSize = size; // 使用原图1/size像素
		options.inPurgeable = true;
		options.inInputShareable = true;
		Bitmap bitmap = null;

		try {
			bitmap = BitmapFactory.decodeStream(inputStream, null, options);
		} catch (Throwable e) {
			e.printStackTrace();
			System.runFinalization();
			System.gc();
			return null;
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
					inputStream = null;
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		if (bitmap == null) {
			return null;
		}

		BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap);
		Drawable drawable = (Drawable) bitmapDrawable;

		if (drawable != null && drawable.getIntrinsicHeight() == 0) {
			bitmap.recycle();
			bitmap = null;
			drawable = null;
			return null;
		}
		return drawable;
	}

	/**
	 * 读取本地Drawable文件
	 * 
	 * @param url
	 * @param savePath
	 * @param size
	 * @param quality
	 * @return
	 * @throws FileNotFoundException
	 */
	public static final Drawable loadDrawableFromLocalByNetUrl(String url,
			String savePath, int size) throws FileNotFoundException {
		String filePath = savePath + generateFileName(url);
		return loadDrawableFromLoaclByLocalPath(filePath, size);
	}

	/**
	 * 保存网络文件
	 * 
	 * @param url
	 * @param savePath
	 * @param useImmediately
	 * @throws IOException
	 * @throws MalformedURLException
	 */
	public static final void saveNetFileAsTxt(String url, String savePath,
			boolean useImmediately, FileLoadCallback callback)
			throws MalformedURLException, IOException {
		InputStream inputStream = getFileInputStreamNet(url, null);
		if (inputStream != null) {
			try {
				saveNetInputStream2SDCardAsFile(url, savePath, null);
				if (useImmediately && callback != null) {
					String txt = inputStream2String(inputStream);
					callback.loadComplete(txt);
				} else if (useImmediately) {
					throw new IllegalArgumentException(
							FileLoadCallback.class.getName()
									+ " can't be null.");
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				inputStream.close();
				inputStream = null;
			}
		}

	}

	/**
	 * 保存网络输入流为Drawable到SDCard
	 * 
	 * @param url
	 * @param savePath
	 * @param size
	 * @param useImmediately
	 * @param callback
	 * @return
	 */
	public static final Drawable saveNetInputStreamAsDrawable(String url,
			String savePath, int size, int quality, boolean useImmediately,
			FileLoadCallback callback) {

		// 产生本地保存名称
		String filePath = savePath + generateFileName(url);

		if (fileExist(url, savePath)) { // 文件已存在本地
			if (callback != null) {
				callback.loadComplete(filePath, null);
			}
			if (useImmediately) {
				try {
					return loadDrawableFromLocalByNetUrl(url, savePath, size);
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
			}
			return null;
		}

		InputStream inputStream = null;
		FileOutputStream fileOutputStream = null;
		try {
			inputStream = getFileInputStreamNet(url, null);
			Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

			fileOutputStream = new FileOutputStream(new File(filePath));
			if (bitmap != null) {
				bitmap.compress(getImageSaveFormat(url), quality,
						fileOutputStream);
				if (useImmediately) {
					BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap);
					Drawable drawable = (Drawable) bitmapDrawable;
					return drawable;
				} else {
					bitmap.recycle();
				}
			}
		} catch (Throwable e) {
			e.printStackTrace();
		} finally {
			if (fileOutputStream != null) {
				try {
					fileOutputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				fileOutputStream = null;
			}
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				inputStream = null;
			}
		}

		return null;
	}

	public static final void saveNetInputStream2SDCardAsFile(String url,
			String savePath, FileLoadCallback callback, boolean useImmediately)
			throws MalformedURLException, IOException {
		if (callback == null) {
			throw new IllegalArgumentException(FileLoadCallback.class.getName()
					+ " can't be null.");
		}
		saveNetInputStream2SDCardAsFile(url, savePath, callback);
	}

	/**
	 * 将网络流以文件形式写到SDCard
	 * 
	 * @param url
	 * @param callback
	 * @throws IOException
	 * @throws MalformedURLException
	 */
	public static final void saveNetInputStream2SDCardAsFile(String url,
			String savePath, FileLoadCallback callback)
			throws MalformedURLException, IOException {

		// 产生本地保存名称
		String fileName = generateFileName(url);

		if (fileExist(url, savePath)) { // 文件已存在本地
			if (callback != null) {
				callback.loadComplete(savePath + fileName, null);
			}
			return;
		}

		// 获取网络输入流
		InputStream inputStream = getFileInputStreamNet(url, null);

		if (SDCardUtils.sdcardAvailable()) { // SDCard可写

			File file = null;
			FileOutputStream fileOutputStream = null;
			try {
				file = new File(savePath + fileName);
				fileOutputStream = new FileOutputStream(file);
				byte[] buffer = new byte[BUFFER_SIZE];
				int len = -1;
				while ((len = inputStream.read(buffer)) > 0) {
					fileOutputStream.write(buffer, 0, len);
				}
				if (callback != null) {
					callback.loadComplete(savePath + fileName, null);
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (fileOutputStream != null) {
					fileOutputStream.close();
					fileOutputStream = null;
				}
				if (file != null) {
					file = null;
				}
				if (inputStream != null) {
					inputStream.close();
					inputStream = null;
				}
			}
		}
	}

	/**
	 * 加载本地文件流
	 * 
	 * @param filePath
	 * @param callback
	 * @return
	 * @throws FileNotFoundException
	 */
	public static final InputStream getFileInputStreamLocal(String filePath)
			throws FileNotFoundException {

		if (!SDCardUtils.sdcardAvailable()) { // SDCard不可用
			return null;
		}

		File file = new File(filePath);

		if (!file.exists()) { // 文件不存在
			return null;
		}

		FileInputStream fileInputStream = new FileInputStream(file);
		return fileInputStream;
	}

	/**
	 * 加载网络文件流
	 * 
	 * @param url
	 * @param callback
	 * @return
	 * @throws IOException
	 * @throws MalformedURLException
	 */
	public static final InputStream getFileInputStreamNet(String url,
			FileLoadCallback callback) throws MalformedURLException,
			IOException {

		HttpURLConnection connection = null;
		connection = (HttpURLConnection) new URL(url).openConnection();
		connection.setConnectTimeout(TIMEOUT);
		connection.setReadTimeout(TIMEOUT);
		connection.setDoInput(true);
		connection.setDoOutput(false);
		connection.setUseCaches(false);

		connection.setRequestMethod("GET");

		if (200 == connection.getResponseCode()) {

			if (callback != null) { // 网络文件输入流获取成功，调用回调接口
				// callback.loadComplete(null, null);
			}
			return connection.getInputStream();
		}
		return null;
	}

	/**
	 * 将输入流转为字符串
	 * 
	 * @param inputStream
	 * @return
	 * @throws IOException
	 */
	public static final String inputStream2String(InputStream inputStream)
			throws IOException {

		ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(
				inputStream.available());
		int len = -1;
		byte[] buffer = new byte[BUFFER_SIZE];

		while ((len = inputStream.read(buffer)) > 0) {
			arrayOutputStream.write(buffer, 0, len);
		}

		String txt = arrayOutputStream.toString();
		arrayOutputStream.close();
		arrayOutputStream = null;

		return txt;
	}

	/**
	 * 判断文件是否存在
	 * 
	 * @param fileName
	 * @param savePath
	 * @return
	 */
	public static final boolean fileExist(String fileName, String savePath) {
		String filePath = savePath + generateFileName(fileName);
		return fileExist(filePath);
	}

	public static final boolean fileExist(String filePath) {
		File file = new File(filePath);
		boolean exist = file.exists();
		file = null;
		return exist;
	}

	/**
	 * 获取文件保存格式
	 * 
	 * @param url
	 * @return
	 */
	public static final CompressFormat getImageSaveFormat(String url) {
		if (url == null) {
			return CompressFormat.PNG;
		}

		int dotIndex = url.lastIndexOf(".");
		if (dotIndex < 0) {
			return CompressFormat.PNG;
		}

		String suffix = url.substring(dotIndex);
		if (".PNG".equalsIgnoreCase(suffix)) {
			return CompressFormat.PNG;
		} else {
			return CompressFormat.JPEG;
		}
	}

	/**
	 * 产生文件本地名称
	 * 
	 * @param fileName
	 * @return
	 */
	public static final String generateFileName(String fileName) {
		if (fileName == null || "".equals(fileName)) {
			return null;
		}
		return DigestUtils.shaHex(fileName);
	}
}
